#! /usr/bin/python

from datetime import date
import ovs.db.error
import ovs.db.schema
import getopt
import os
import re
import sys

argv0 = sys.argv[0]

def printEdge(tableName, type, baseType, label):
    if baseType.ref_table_name:
        if type.n_min == 0:
            if type.n_max == 1:
                arity = "?"
            elif type.n_max == sys.maxint:
                arity = "*"
            else:
                arity = "{,%d}" % type.n_max
        elif type.n_min == 1:
            if type.n_max == 1:
                arity = ""
            elif type.n_max == sys.maxint:
                arity = "+"
            else:
                arity = "{1,%d}" % type.n_max

        options = {}
        options['label'] = '"%s%s"' % (label, arity)
        if baseType.ref_type == 'weak':
            options['style'] = 'dotted'
        print "\t%s -> %s [%s];" % (
            tableName,
            baseType.ref_table_name,
            ', '.join(['%s=%s' % (k,v) for k,v in options.items()]))

def schemaToDot(schemaFile, arrows):
    schema = ovs.db.schema.DbSchema.from_json(ovs.json.from_file(schemaFile))

    print "digraph %s {" % schema.name
    print '\trankdir=LR;'
    print '\tsize="6.5,4";'
    print '\tmargin="0";'
    print "\tnode [shape=box];"
    if not arrows:
        print "\tedge [dir=none, arrowhead=none, arrowtail=none];"
    for tableName, table in schema.tables.iteritems():
        options = {}
        if table.is_root:
            options['style'] = 'bold'
        print "\t%s [%s];" % (
            tableName,
            ', '.join(['%s=%s' % (k,v) for k,v in options.items()]))
        for columnName, column in table.columns.iteritems():
            if column.type.value:
                printEdge(tableName, column.type, column.type.key, "%s key" % columnName)
                printEdge(tableName, column.type, column.type.value, "%s value" % columnName)
            else:
                printEdge(tableName, column.type, column.type.key, columnName)
    print "}";

def usage():
    print """\
%(argv0)s: compiles ovsdb schemas to graphviz format
Prints a .dot file that "dot" can render to an entity-relationship diagram
usage: %(argv0)s [OPTIONS] SCHEMA
where SCHEMA is an OVSDB schema in JSON format

The following options are also available:
  --no-arrows                 omit arrows from diagram
  -h, --help                  display this help message
  -V, --version               display version information\
""" % {'argv0': argv0}
    sys.exit(0)

if __name__ == "__main__":
    try:
        try:
            options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
                                              ['no-arrows',
                                               'help', 'version',])
        except getopt.GetoptError, geo:
            sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
            sys.exit(1)

        arrows = True
        for key, value in options:
            if key == '--no-arrows':
                arrows = False
            elif key in ['-h', '--help']:
                usage()
            elif key in ['-V', '--version']:
                print "ovsdb-dot (Open vSwitch) 2.5.0"
            else:
                sys.exit(0)

        if len(args) != 1:
            sys.stderr.write("%s: exactly 1 non-option argument required "
                             "(use --help for help)\n" % argv0)
            sys.exit(1)

        schemaToDot(args[0], arrows)

    except ovs.db.error.Error, e:
        sys.stderr.write("%s: %s\n" % (argv0, e.msg))
        sys.exit(1)

# Local variables:
# mode: python
# End:
